import moment from 'moment'
import * as _ from 'lodash'
import {G} from "@/views/flow/globalVar.js";
const DRAWING_ITEMS = 'drawingItems'
const DRAWING_ID = 'idGlobal'
const TREE_NODE_ID = 'treeNodeId'
const FORM_CONF = 'formConf'
const Message = {
	error: () => {
	},
	success: () => {
	},
	info: () => {
	},
	warning: () => {
	},
	closeAll: () => {
	}
}
export function oaMsg() {
	Message.closeAll()
	Message.apply(this,
		arguments)
}
oaMsg['error'] = function () {
	Message.closeAll()
	Message['error'].apply(this,
		arguments)
}
oaMsg['success'] = function () {
	Message.closeAll()
	Message['success'].apply(this,
		arguments)
}
oaMsg['info'] = function () {
	Message.closeAll()
	Message['info'].apply(this,
		arguments)
}
oaMsg['warning'] = function () {
	Message.closeAll()
	Message['warning'].apply(this,
		arguments)
}
window.oaMsg = oaMsg
export function getDrawingList() {
	const str = localStorage.getItem(DRAWING_ITEMS)
	if (!['undefined',
		'null'].includes(str)) return JSON.parse(str)
	return null
}
export function saveDrawingList(list) {
	localStorage.setItem(DRAWING_ITEMS,
		JSON.stringify(list))
}
export function getIdGlobal() {
	const str = localStorage.getItem(DRAWING_ID)
	if (+str) return parseInt(str,
		10)
	return 100
}
export function saveIdGlobal(id) {
	localStorage.setItem(DRAWING_ID,
		`${id}`)
}
export function getTreeNodeId() {
	const str = localStorage.getItem(TREE_NODE_ID)
	if (str) return parseInt(str,
		10)
	return 100
}
export function saveTreeNodeId(id) {
	localStorage.setItem(TREE_NODE_ID,
		`${id}`)
}
export function getFormConf() {
	const str = localStorage.getItem(FORM_CONF)
	if (str) return JSON.parse(str)
	return null
}
export function saveFormConf(obj) {
	localStorage.setItem(FORM_CONF,
		JSON.stringify(obj))
}
/**
 * num 小于0，左缩进num*2个空格； 大于0，右缩进num*2个空格。
 * @param {string} str 代码
 * @param {number} num 缩进次数
 * @param {number} len 【可选】缩进单位，空格数
 */
export function indent(str,
                       num,
                       len = 2) {
	if (num === 0) return str
	const isLeft = num < 0
	const result = []
	let reg
	let spaces = ''
	if (isLeft) {
		num *= -1
		reg = new RegExp(`(^\\s{0,${num * len}})`, 'g')
	} else {
		for (let i = 0; i < num * len; i++) spaces += ' '
	}
	str.split('\n')
		.forEach(line => {
			line = isLeft ? line.replace(reg,
				'') : spaces + line
			result.push(line)
		})
	return result.join('\n')
}
// 首字母大小
export function titleCase(str) {
	return str.replace(/( |^)[a-z]/g,
		L => L.toUpperCase())
}
// 下划转驼峰
export function camelCase(str) {
	return str.replace(/-[a-z]/g,
		str1 => str1.substr(-1)
			.toUpperCase())
}
export function isNumberStr(str) {
	return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}
//return (${infoFormat}).apply(this,[value,tagName])
// vm 用来在某些时候获取不到正确的表单数据 全局进行搜索的hack手段
export const exportDefault = `export default `
export const beautifierConf = {
	html: {
		indent_size: '2',
		indent_char: ' ',
		max_preserve_newlines: '-1',
		preserve_newlines: false,
		keep_array_indentation: false,
		break_chained_methods: false,
		indent_scripts: 'separate',
		brace_style: 'end-expand',
		space_before_conditional: true,
		unescape_strings: false,
		jslint_happy: false,
		end_with_newline: true,
		wrap_line_length: '110',
		indent_inner_html: true,
		comma_first: false,
		e4x: true,
		indent_empty_lines: true
	},
	js: {
		indent_size: '2',
		indent_char: ' ',
		max_preserve_newlines: '-1',
		preserve_newlines: false,
		keep_array_indentation: false,
		break_chained_methods: false,
		indent_scripts: 'normal',
		brace_style: 'end-expand',
		space_before_conditional: true,
		unescape_strings: false,
		jslint_happy: true,
		end_with_newline: true,
		wrap_line_length: '110',
		indent_inner_html: true,
		comma_first: false,
		e4x: true,
		indent_empty_lines: true
	}
}
function stringify(obj) {
	return JSON.stringify(obj,
		(key,
		 val) => {
			if (typeof val === 'function') {
				return `${val}`
			}
			return val
		})
}
function parse(str) {
	JSON.parse(str,
		(k,
		 v) => {
			if (v.indexOf && v.indexOf('function') > -1) {
				return eval(`(${v})`)
			}
			return v
		})
}
export function jsonClone(obj) {
	return parse(stringify(obj))
}
export const loadScript = (src,
                           callback) => {
	const cb = callback || (() => {
	})
	const $script = document.createElement('script')
	$script.src = src
	$script.id = src
	document.body.appendChild($script)
	const onEnd = 'onload' in $script ? stdOnEnd : ieOnEnd
	onEnd($script)
	function stdOnEnd(script) {
		script.onload = () => {
			this.onerror = this.onload = null
			cb(null,
				script)
		}
		script.onerror = () => {
			this.onerror = this.onload = null
			cb(new Error(`Failed to load ${src}`),
				script)
		}
	}
	function ieOnEnd(script) {
		script.onreadystatechange = () => {
			if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
			this.onreadystatechange = null
			cb(null,
				script)
		}
	}
}
export const openLogError = ({e}) => {
	//console.warn(e)
}
export function getParams(params) {
	let str = ''
	let index = 0
	if (params) {
		for (const i in params) {
			index++
			if (index == 1) {
				str += `?${i}=${params[i]}`
			} else {
				str += `&${i}=${params[i]}`
			}
		}
	}
	return str
}
export const setDefaultValue = (val) => {
	if (Array.isArray(val)) {
		return JSON.stringify(val)
	}
	if (['string',
		'number'].indexOf(val) > -1) {
		return val
	}
	if (typeof val === 'boolean') {
		return `${val}`
	}
	if (typeof val === 'object') {
		return JSON.stringify(val)
	}
	return val
}
export const iconList = (iconPath) => {
	const req = require.context(iconPath,
		false,
		/\.png$/)
	const iconList = req.keys()
		.sort((a,
		       b) => {
			return Number(a.split('./A(')[1].split(').png')[0]) - Number(b.split('./A(')[1].split(').png')[0])
		})
		.map((t,
		      idx) => ({
			src: req(t),
			id: idx
		}))
	return iconList
}
// 传this默认从url query获取
// 不传this,自己判断
export const getDevice = (context) => {
	if (context) {
		if (context.hasOwnProperty('$route') && _.get(context.$route.query,
			'device',
			false)) {
			return context.$route.query.device || 'pc'
		}
	}
	if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
		return 'mobile'
	} else {
		return 'pc'
	}
}
// 注意了,defaultValue的类型只能是string 也就是value只能是string,其他类型都会返回空
export const formatDefaultValueByType = function (type,
                                                  value) {
	if (!type) {
		return value
	}
	if (!value && value != 0) {
		return
	}
	if (typeof value !== 'string') {
		return
	}
	switch (type) {
		case 'Object':
		case 'Array': {
			let result = undefined
			try {
				result = JSON.parse(value)
			} catch (e) {
				openLogError({e})
			}
			return result
		}
		default: {
			return value
		}
	}
}
export const unFormatDefaultValueByType = function (type,
                                                    value) {
	if (!type) {
		return value
	}
	if (!value && value != 0) {
		return
	}
	switch (type) {
		case 'Object':
		case 'Array': {
			const result = JSON.stringify(value)
			return result
		}
		default: {
			return value
		}
	}
}
export const digitUppercase = function (n) {
	try {
		return getAmountChinese(n)
	} catch (e) {
		let result = ''
		try {
			var fraction = ['角',
				'分']
			var digit = ['零',
				'壹',
				'贰',
				'叁',
				'肆',
				'伍',
				'陆',
				'柒',
				'捌',
				'玖']
			var unit = [['元',
				'万',
				'亿'],
				['',
					'拾',
					'佰',
					'仟']]
			var head = n < 0 ? '欠' : ''
			n = Math.abs(n)
			var s = ''
			for (var i = 0; i < fraction.length; i++) {
				s += (digit[Math.floor(n * 10 * Math.pow(10,
					i)) % 10] + fraction[i]).replace(/零./,
					'')
			}
			s = s || '整'
			n = Math.floor(n)
			for (var i = 0; i < unit[0].length && n > 0; i++) {
				var p = ''
				for (var j = 0; j < unit[1].length && n > 0; j++) {
					p = digit[n % 10] + unit[1][j] + p
					n = Math.floor(n / 10)
				}
				s = p.replace(/(零.)*零$/,
					'')
					.replace(/^$/,
						'零') + unit[0][i] + s
			}
			result = head + s.replace(/(零.)*零元/,
				'元')
				.replace(/(零.)+/g,
					'零')
				.replace(/^整$/,
					'零元整')
		} catch (e) {
			openLogError(e)
		}
		return result
	}
	return ''
}
/**
 * 处理参数对象中的字符串首尾空格<br>
 * @param paramObj
 * @return paramObj 处理之后的 paramObj 的原型链
 */
export function stringTrimHandle(paramObj) {
	if (paramObj && Object.is(paramObj)) {
		Object.keys(paramObj)
			.forEach(item => {
				paramObj[item] = typeof paramObj[item] === 'string' ? paramObj[item].trim() : paramObj[item]
			})
	}
	return paramObj
}
/**
 * 非法字符串处理<br>
 * <b>例如：</b>
 * <ul>
 *   <li>{}|\^[]`~ ：某一些网关或者传输代理会篡改这些字符</li>
 *   <li>%：百分号本身用作对不安全字符进行编码时使用的特殊字符，因此本身需要编码</li>
 *   <li>#：通常用于表示书签或者锚点</li>
 *   <li>引号以及<>：引号和尖括号通常用于在普通文本中起到分隔Url的作用</li>
 *   <li>空格：Url在传输的过程，或者用户在排版的过程，或者文本处理程序在处理Url的过程，都有可能引入无关紧要的空格，或者将那些有意义的空格给去掉</li>
 * </ul>
 * @param paramObject
 * @param url
 */
export function illegalStringHandle(paramObject,
                                    url) {
	// get参数编码
	if (paramObject) {
		url += '?'
		Object.keys(paramObject)
			.forEach(item => {
				if (paramObject[item] == 0 || paramObject[item]) {
					url += `${item}=${encodeURIComponent(paramObject[item])}&`
				}
			})
		url = url.substring(0,
			url.length - 1)
	}
	return url
}
/**
 * <p>使用 dataList 数组中每一条数据项的 filedName 属性对应的值进行分组</p>
 * @param {Array} dataList    列表数据
 * @param {String} fieldName  字段名称
 * @return {Object} groupResult
 */
export function groupByField(dataList,
                             fieldName) {
	const groupResult = {}
	if (!dataList || dataList.length === 0) return groupResult
	dataList.forEach(row => {
		// 1. 获取当前数据项属性 fieldName 对应的值，用来最为 groupResult 的属性
		const groupField = JSON.stringify(row[fieldName])
		// 2. 用 groupField 作为 groupResult 的属性，进行赋值，如果是第一次获取该属性，那么初始化 groupResult[groupField] = []
		groupResult[groupField] = groupResult[groupField] || []
		// 3. 将 row 添加到 groupResult[groupField] 对应的分组数组中去
		groupResult[groupField].push(row)
	})
	return groupResult
}
export function getTimeState() {
	// 获取当前时间
	const timeNow = new Date()
	// 获取当前小时
	const hours = timeNow.getHours()
	// 设置默认文字
	let text = ``
	// 判断当前时间段
	if (hours >= 0 && hours <= 10) {
		text = `早上好`
	} else if (hours > 10 && hours <= 14) {
		text = `中午好`
	} else if (hours > 14 && hours <= 18) {
		text = `下午好`
	} else if (hours > 18 && hours <= 24) {
		text = `晚上好`
	}
	// 返回当前时间段对应的状态
	return text
}
// 如果formId为undefined,则重新生成formId
export const createNullFormId = (confFields,
                                 formIdArr) => {
	confFields.forEach((item,
	                    index) => {
		if (item.formId == undefined) {
			const max = formIdArr.reduce((prev,
			                              next) => {
				if (prev == undefined) prev = 0
				if (next == undefined) next = 0
				return prev - next >= 0 ? prev : next
			})
			if (!isNaN(max)) {
				item.formId = max + 1
			} else {
				item.formId = 11000
			}
		}
		if (item.hasOwnProperty('children')) {
			createNullFormId(item.children,
				formIdArr)
		}
	})
}
// 设置表单权限
export const autoOperate = (processConf,
                            formIdArr,
                            fields) => {
	// 后台返回的是string 所以这里要转,要不然formIdArr.includes(res.formId)会返回false
	formIdArr = formIdArr.map((res) => {
		if (res == undefined) {
			res = '9999'
		} else {
			res = res.toString()
		}
		return res
	})
	if (processConf && processConf.hasOwnProperty('properties') &&
		processConf.properties.hasOwnProperty('formOperates')) {
		const formOperates = processConf.properties.formOperates.filter((res) => {
			return formIdArr.some((sires) => {
				return sires.toString() == res.formId
			})
		})
		formIdArr.forEach((res) => {
			if (formOperates.every((item,
			                        index) => {
				return item.formId != res
			})) {
				let vModel = undefined
				let target = fields.find((fres) => {
					return fres.formId == res
				})
				if (target) {
					vModel = target.vModel
				}
				let temp = {}
				try {
					temp = JSON.parse(JSON.stringify(processConf.properties.formOperates[0]))
				} catch (e) {
				}
				if (processConf.type == 'start') {
					temp.formOperate = G.FORM_OPERATE.EDIT
				} else {
					temp.formOperate = G.FORM_OPERATE.READ
				}
				temp.formId = res
				if (!vModel) {
					throw new Error("找不到vModel")
				} else {
					temp.vModel = vModel
				}
				formOperates.push(temp)
			}
		})
		processConf.properties.formOperates = formOperates
	} else {
		if (!processConf.hasOwnProperty('properties')) {
			processConf['properties'] = {}
		}
		if (!processConf.properties.hasOwnProperty('formOperates')) {
			processConf.properties.formOperates = []
		}
		autoOperate(processConf,
			formIdArr,
			fields)
	}
	if ('childNode' in processConf && processConf.childNode != undefined) {
		autoOperate(processConf.childNode,
			formIdArr,
			fields)
	}
	if ('conditionNodes' in processConf && processConf.conditionNodes != undefined &&
		processConf.conditionNodes.length > 0) {
		processConf.conditionNodes.forEach((res) => {
			autoOperate(res,
				formIdArr,
				fields)
		})
	}
}
// 获取表单所有formId
export const getformid = (res,
                          formIdArr) => {
	res.forEach((a) => {
		formIdArr.push(a.formId)
		if (a.hasOwnProperty('children') && a.children.length > 0) {
			getformid(a.children,
				formIdArr)
		}
	})
}
//打散表单字段
export const getformFields = (res,
                              formFields) => {
	res.forEach((a) => {
		formFields.push(a)
		if (a.hasOwnProperty('children') && a.children.length > 0) {
			getformFields(a.children,
				formFields)
		}
	})
}
// 日期默认值
export const dateValueSet = (resData,
                             el) => {
	// 是否刚发起
	const processTask = _.get(resData,
		'processTask',
		false)
	// 没有任务状态的,是发起节点,需要自动带出日期
	if (!processTask) {
		// 如果没有设置默认值,需要带出默认今日为初始日期
		if (!el.hasOwnProperty('defaultValue') || !el.defaultValue) {
			if (el.format && el.format.toUpperCase() == 'YYYY-MM-DD HH:MM:SS') {
				el.defaultValue = moment(new Date())
					.format('YYYY-MM-DD HH:mm:ss')
			} else if (el.format && el.format.toUpperCase() == 'YYYY-MM-DD') {
				el.defaultValue = moment(new Date())
					.format('YYYY-MM-DD')
			} else if (!el.format) {
				el.defaultValue = moment(new Date())
					.format('YYYY-MM-DD')
			}
		}
		// 如果设置成默认值为null,存后台的是null字符串,这个时候,不需要带出默认今日.
		else if (el.defaultValue == 'null' || el.defaultValue == null || el.defaultValue == '') {
			el.defaultValue = null
		}
		// 兼容撤回,有默认值得,需要带出默认值
		else if (typeof el.defaultValue === 'string') {
		}
		// 暂时不支持设置默认值
		else {
			el.defaultValue = null
		}
	}
	// 有任务状态,说明是已经发起审批后的节点,包括被驳回的 原来如果是空的,要保持为空的状态,不能设置默认日期为今天
	else {
		if (!el.hasOwnProperty('defaultValue') || !el.defaultValue || el.defaultValue == 'null') {
			el.defaultValue = null
		}
	}
}
export const praseValue = function (data,
                                    obj) {
	if (typeof data === 'object') {
		const o = JSON.stringify(data)
		let arr = o.match(/\"label\"\:\".[^,]*/ig)
		if (typeof arr === 'object' && Array.isArray(arr) && arr.length > 0) {
			let str = ''
			arr.forEach((item,
			             index) => {
				const d = index == arr.length - 1 ? '' : ','
				str += item.split(':')[1].replace(/\"/ig,
					'')
					.replace(/\}/ig,
						'') + d
			})
			return str
		} else {
			return ''
		}
	} else {
		return typeof data === 'undefined' ? '' : data
	}
}
window.toolsPraseValue = praseValue
// 单引号被成功提交上去了,接收的时候,需要去掉
export const reqFormatFieldData = (res) => {
	const r = res
	try {
		for (var i in r) {
			if (r[i] && Array.isArray(r[i]) && r[i].length > 0) {
				r[i] = r[i].map((item,
				                 index) => {
					if (item && typeof item === 'object') {
						for (var a in item) {
							if (/'/.test(item[a])) {
								item[a] = item[a].replace(/\'/g,
									'')
							}
						}
					}
					return item
				})
			}
		}
	} catch (e) {
		openLogError(e)
	}
	return r
}
// 生成随机字符串
export function randomString(e) {
	e = e || 32
	var t = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
	var a = t.length
	var n = ''
	for (var i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a))
	return n
}
// 格式化表单数据 只做反显用,不做数据提交
// 注意下面的文件用了相同的方法,改的时候要一起改
// obj 是一个对象
export function infoFormat(value,
                           tagName,
                           obj) {
	let params = {}
	if (obj != null) {
		params = obj
	}
	let result = ''
	try {
		if (tagName == 'po-change-selection-field') {
			result = '字段选择器标识'
		} else if (value === '' || value === null || value === 'null' || value === 'undefined' || value === undefined) {
			if (tagName && tagName == 'el-input-number') {
				result = 0
			} else {
				result = ''
			}
		} else if (typeof value === 'number') {
			result = value
			if (value === 0 || value === '' || isNaN(result)) {
				result = 0
			}
		} else if (typeof value === 'object') {
			switch (tagName) {
				/*case 'fc-date-duration': {
					result = value.join(' 至 ')
					break
				}*/
				default: {
					result = praseValue(value,
						obj)
				}
			}
		} else {
			result = value
		}
	} catch (e) {
		// 注意，这里不能用openLogError，否则编译的时候会报错
		console.error({e})
	}
	// 是否要带出大写金额
	if (params.hasOwnProperty('digitUppercase') && params.digitUppercase == true) {
		const str = result
		result = str + '\n' + digitUppercase(str)
	}
	return result
}
window.toolsInfoFormat = infoFormat
export function copyFieldInfo({
	                              value,
	                              tag
                              }) {
	try {
		const val = infoFormat(value,
			tag)
		if (!val && val !== 0) {
		} else {
			const dummy = document.createElement('textarea')
			document.body.appendChild(dummy)
			dummy.value = val
			dummy.select()
			document.execCommand('copy')
			document.body.removeChild(dummy)
			oaMsg({
				customClass: 'copy-success-tip',
				dangerouslyUseHTMLString: true,
				message: `<div class="msg"> 已复制 "${val}" 🎉 </div>`,
				type: 'success',
				duration: 4 * 1000
			})
		}
	} catch (e) {
		oaMsg({
			customClass: 'copy-success-tip',
			dangerouslyUseHTMLString: true,
			oaMsg: `<div class="msg"> 复制失败 </div>`,
			type: 'info',
			duration: 3 * 1000
		})
	}
}
window.copyFieldInfo = copyFieldInfo
// 提交表单前置事件
// 参数时间戳
export function getDayOfWeek(date) {
	const week = moment(date)
		.day()
	switch (week) {
		case 1:
			return '星期一'
		case 2:
			return '星期二'
		case 3:
			return '星期三'
		case 4:
			return '星期四'
		case 5:
			return '星期五'
		case 6:
			return '星期六'
		case 0:
			return '星期日'
	}
}
// 获取当前运行环境
// 取精确度
export function setAccuracy(value,
                            accuracy) {
	return Math.floor(value * Math.pow(10,
		accuracy)) / Math.pow(10,
		accuracy)
}
// 加逗号拼写字符串
// 传 [{a:"1",b:"2"},{a:"11",b:{"22"}}]
export function setComma({
	                         arr,
	                         key
                         }) {
	return arr.reduce((result,
	                   cur,
	                   curIndex) => {
			var comma = curIndex == arr.length - 1 ? '' : ','
			if (cur && cur.hasOwnProperty(key) && cur[key]) {
				return result + key + ' ' + cur[key] + comma
			} else {
				return result + key + ' ' + '空' + comma
			}
		},
		'')
}
// 日志 表格处理哪些字段需要转成username
// cols 表格的引用
// 需要转换成username的table head key 数组
// keyArr不传的时候，所有字段都需要转username
export function changeLogTableFieldToUserName({
	                                              cols,
	                                              keyArr
                                              }) {
	// 如果需要处理username
	if (keyArr && Array.isArray(keyArr) && keyArr.length > 0) {
		try {
			cols = cols.map((item) => {
				keyArr.forEach((res) => {
					if (item.hasOwnProperty('property') && item.property == res) {
						item.getUserName = true
					}
				})
				return item
			})
		} catch (e) {
		}
	} else {
		cols = cols.map((item) => {
			item.getUserName = true
			return item
		})
	}
	return cols
}
//非空数组
export function isNotEmptyArray(arr) {
	return arr && Array.isArray(arr) && arr.length > 0
}
/**
 * 金额转中文
 * 思路：
 * 个 十   百   千   万
 *    十万 百万 千万 亿
 *    十亿 百亿 千亿
 * 1  2    3    4    5
 *    6    7    8    9
 *    10
 *
 */
export function getAmountChinese(money) {
	//汉字的数字
	let cnNums = new Array('零',
		'壹',
		'贰',
		'叁',
		'肆',
		'伍',
		'陆',
		'柒',
		'捌',
		'玖')
	//基本单位
	let cnIntRadice = new Array('',
		'拾',
		'佰',
		'仟')
	//对应整数部分扩展单位
	let cnIntUnits = new Array('',
		'万',
		'亿',
		'兆')
	//对应小数部分单位
	let cnDecUnits = new Array('角',
		'分',
		'毫',
		'厘')
	//整数金额时后面跟的字符
	let cnInteger = '整'
	//整型完以后的单位
	let cnIntLast = '元'
	//最大处理的数字
	let maxNum = 999999999999999.9999
	//金额整数部分
	let integerNum
	//金额小数部分
	let decimalNum
	//输出的中文金额字符串
	let chineseStr = ''
	//分离金额后用的数组，预定义
	let parts
	if (money == '') {
		return ''
	}
	money = parseFloat(money)
	if (money >= maxNum) {
		//超出最大处理数字
		return ''
	}
	if (money == 0) {
		chineseStr = cnNums[0] + cnIntLast + cnInteger
		return chineseStr
	}
	//转换为字符串
	money = money.toString()
	if (money.indexOf('.') == -1) {
		integerNum = money
		decimalNum = ''
	} else {
		parts = money.split('.')
		integerNum = parts[0]
		decimalNum = parts[1].substr(0,
			4)
	}
	//获取整型部分转换
	if (parseInt(integerNum,
		10) > 0) {
		let zeroCount = 0
		let IntLen = integerNum.length
		for (let i = 0; i < IntLen; i++) {
			let n = integerNum.substr(i,
				1)
			let p = IntLen - i - 1
			let q = p / 4
			let m = p % 4
			if (n == '0') {
				zeroCount++
			} else {
				if (zeroCount > 0) {
					chineseStr += cnNums[0]
				}
				//归零
				zeroCount = 0
				chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
			}
			if (m == 0 && zeroCount < 4) {
				chineseStr += cnIntUnits[q]
			}
		}
		chineseStr += cnIntLast
	}
	//小数部分
	if (decimalNum != '') {
		let decLen = decimalNum.length
		for (let i = 0; i < decLen; i++) {
			let n = decimalNum.substr(i,
				1)
			if (n != '0') {
				chineseStr += cnNums[Number(n)] + cnDecUnits[i]
			}
		}
	}
	if (chineseStr == '') {
		chineseStr += cnNums[0] + cnIntLast + cnInteger
	} else if (decimalNum == '') {
		chineseStr += cnInteger
	}
	return chineseStr
}
/**
 * 计算两个时间差经历的时间的文字描述
 * @param {*} timestamp - 毫秒
 */
export const timeCalculate = (start,
                              end) => {
	const label = ['分钟',
		'小时',
		'天',
		'月',
		'年']
	const unit = [60,
		60,
		24,
		30,
		12]
	let restTime = Math.floor((end - start) / 1000)
	let res = ''
	for (let i = 0, len = unit.length; i < len; i++) {
		const pos = len - i // 从年开始算，分钟换算成年 === Math.pow(60, 4)
		const temp = unit.slice(0,
			pos)
			.reduce((p,
			         c) => p * c,
				1)
		const time = Math.floor(restTime / temp)
		time > 0 && (res += time + label[pos - 1])
		restTime -= time * temp
	}
	return res
}
/**
 * 简易防抖函数
 * @param {Function} func -防抖目标函数
 * @param {Number}} gap - 防抖时间间隔
 */
export const simpleDebounce = (func,
                               gap) => {
	let timer
	return function () {
		timer && clearTimeout(timer)
		timer = setTimeout(function () {
				func.apply(this,
					arguments)
			},
			gap)
	}
}
/**
 * 下划线转驼峰
 * @param {String} name - 字符串
 */
export const toHump = name => name.replace(/\_(\w)/g,
	function (all,
	          letter) {
		return letter.toUpperCase()
	})
/**
 * 将用户输入的连续单个数字合并为一个数
 * @param {Array} expressions - 记录计算表达式的数组
 * @returns {Array} 新的数组
 */

export const mergeNumberOfExps = expressions => {
	const res = []
	const isNumChar = n => /^[\d|\.]$/.test(n)
	for (let i = 0; i < expressions.length; i++) {
		if (i > 0 && isNumChar(expressions[i - 1]) && isNumChar(expressions[i])) {
			res[res.length - 1] += expressions[i]
			continue
		}
		res.push(expressions[i])
	}
	return res
}
/**
 * 校验表达式是否符合计算法则
 * @param {Array} expressions - 合并数字后的表达式数组
 * @returns {Boolean}
 */
export const validExp = (expressions,
                         mergeNum = true) => {
	const temp = mergeNum ? mergeNumberOfExps(expressions) : expressions
	const arr = temp.filter(t => !'()'.includes(t))
	// 去括号后 length应该为奇数  并且第一个字符和最后一个字符应该为数字而非计算符号
	if (temp.length % 2 === 0 || arr.length % 2 === 0 || Number.isNaN(+arr[0]) || Number.isNaN(+arr[arr.length - 1])) {
		return false
	}
	for (let i = 0; i < arr.length - 1; i += 2) {
		if (typeof (+arr[i]) !== 'number' || !Number.isNaN(+arr[i + 1])) return false
	}
	return true
}
/**
 * 中缀转后缀（逆波兰 Reverse Polish Notation）
 * @param {Array} exps - 中缀表达式数组
 */
export const toRPN = exps => {
	const s1 = [] // 符号栈
	const s2 = [] // 输出栈
	const getTopVal = (stack) => stack.length > 0 ? stack[stack.length - 1] : null
	const levelCompare = (c1,
	                      c2) => {
		const getIndex = c => ['+-',
			'×÷',
			'()'].findIndex(t => t.includes(c))
		return getIndex(c1) - getIndex(c2)
	}
	exps.forEach(t => {
		if (typeof t === 'string' && Number.isNaN(Number(t))) { // 是符号
			if (t === '(') {
				s1.push(t)
			} else if (t === ')') {
				let popVal
				do {
					popVal = s1.pop()
					popVal !== '(' && s2.push(popVal)
				} while (s1.length && popVal !== '(')
			} else {
				let topVal = getTopVal(s1)
				if (!topVal) { // s1 为空 直接push
					s1.push(t)
				} else {
					while (topVal && topVal !== '(' && levelCompare(topVal,
						t) >= 0) { // 优先级 >= t 弹出到s2
						s2.push(s1.pop())
						topVal = getTopVal(s1)
					}
					s1.push(t)
				}
			}
			return
		}
		s2.push(t) // 数字直接入栈
	})
	while (s1.length) {
		s2.push(s1.pop())
	}
	return s2
}
/**
 * 计算后缀表达式的值
 * @param {Array} rpnExps - 后缀表达式
 */
export const calcRPN = rpnExps => {
	rpnExps = rpnExps.concat()
	const calc = (x,
	              y,
	              type) => {
		let a1 = Number(x), a2 = Number(y)
		switch (type) {
			case '+':
				return a1 + a2
			case '-':
				return a1 - a2
			case '×':
				return a1 * a2
			case '÷':
				return a1 / a2
		}
	}
	for (let i = 2; i < rpnExps.length; i++) {
		if ('+-×÷'.includes(rpnExps[i])) {
			let val = calc(rpnExps[i - 2],
				rpnExps[i - 1],
				rpnExps[i])
			rpnExps.splice(i - 2,
				3,
				val)
			i = i - 2
		}
	}
	return rpnExps[0]
}
/**
 * 表格时间格式化
 */
export function formatDate(cellValue) {
	if (cellValue == null || cellValue == '') return ''
	var date = new Date(cellValue)
	var year = date.getFullYear()
	var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
	var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
	var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
	var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
	var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
	return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
}
/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time,
                           option) {
	if (('' + time).length === 10) {
		time = parseInt(time) * 1000
	} else {
		time = +time
	}
	const d = new Date(time)
	const now = Date.now()
	const diff = (now - d) / 1000
	if (diff < 30) {
		return '刚刚'
	} else if (diff < 3600) {
		// less 1 hour
		return Math.ceil(diff / 60) + '分钟前'
	} else if (diff < 3600 * 24) {
		return Math.ceil(diff / 3600) + '小时前'
	} else if (diff < 3600 * 24 * 2) {
		return '1天前'
	}
	if (option) {
		return parseTime(time,
			option)
	} else {
		return (d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分')
	}
}
/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
	url = url == null ? window.location.href : url
	const search = url.substring(url.lastIndexOf('?') + 1)
	const obj = {}
	const reg = /([^?&=]+)=([^?&=]*)/g
	search.replace(reg,
		(rs,
		 $1,
		 $2) => {
			const name = decodeURIComponent($1)
			let val = decodeURIComponent($2)
			val = String(val)
			obj[name] = val
			return rs
		})
	return obj
}
/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
	// returns the byte length of an utf8 string
	let s = str.length
	for (var i = str.length - 1; i >= 0; i--) {
		const code = str.charCodeAt(i)
		if (code > 0x7f && code <= 0x7ff) {
			s++
		} else if (code > 0x7ff && code <= 0xffff) s += 2
		if (code >= 0xDC00 && code <= 0xDFFF) i--
	}
	return s
}
/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
	const newArray = []
	for (let i = 0; i < actual.length; i++) {
		if (actual[i]) {
			newArray.push(actual[i])
		}
	}
	return newArray
}
/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
	if (!json) return ''
	return cleanArray(Object.keys(json)
		.map(key => {
			if (json[key] === undefined) return ''
			return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
		}))
		.join('&')
}
/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
	const search = url.split('?')[1]
	if (!search) {
		return {}
	}
	return JSON.parse('{"' + decodeURIComponent(search)
		.replace(/"/g,
			'\\"')
		.replace(/&/g,
			'","')
		.replace(/=/g,
			'":"')
		.replace(/\+/g,
			' ') + '"}')
}
/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
	const div = document.createElement('div')
	div.innerHTML = val
	return div.textContent || div.innerText
}
/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target,
                            source) {
	if (typeof target !== 'object') {
		target = {}
	}
	if (Array.isArray(source)) {
		return source.slice()
	}
	Object.keys(source)
		.forEach(property => {
			const sourceProperty = source[property]
			if (typeof sourceProperty === 'object') {
				target[property] = objectMerge(target[property],
					sourceProperty)
			} else {
				target[property] = sourceProperty
			}
		})
	return target
}
/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element,
                            className) {
	if (!element || !className) {
		return
	}
	let classString = element.className
	const nameIndex = classString.indexOf(className)
	if (nameIndex === -1) {
		classString += '' + className
	} else {
		classString = classString.substr(0,
			nameIndex) + classString.substr(nameIndex + className.length)
	}
	element.className = classString
}
/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
	if (type === 'start') {
		return new Date().getTime() - 3600 * 1000 * 24 * 90
	} else {
		return new Date(new Date().toDateString())
	}
}
/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounceWait(func,
                             wait,
                             immediate) {
	let timeout, args, context, timestamp, result
	const later = function () {
		// 据上一次触发时间间隔
		const last = +new Date() - timestamp
		// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
		if (last < wait && last > 0) {
			timeout = setTimeout(later,
				wait - last)
		} else {
			timeout = null
			// 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
			if (!immediate) {
				result = func.apply(context,
					args)
				if (!timeout) context = args = null
			}
		}
	}
	return function (...args) {
		context = this
		timestamp = +new Date()
		const callNow = immediate && !timeout
		// 如果延时不存在，重新设定延时
		if (!timeout) timeout = setTimeout(later,
			wait)
		if (callNow) {
			result = func.apply(context,
				args)
			context = args = null
		}
		return result
	}
}
/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
	if (!source && typeof source !== 'object') {
		throw new Error('error arguments',
			'deepClone')
	}
	const targetObj = source.constructor === Array ? [] : {}
	Object.keys(source)
		.forEach(keys => {
			if (source[keys] && typeof source[keys] === 'object') {
				targetObj[keys] = deepClone(source[keys])
			} else {
				targetObj[keys] = source[keys]
			}
		})
	return targetObj
}
/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
	return Array.from(new Set(arr))
}
/**
 * @returns {string}
 */
export function createUniqueString() {
	const timestamp = +new Date() + ''
	const randomNum = parseInt((1 + Math.random()) * 65536) + ''
	return (+(randomNum + timestamp)).toString(32)
}
/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele,
                         cls) {
	return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
}
/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele,
                         cls) {
	if (!hasClass(ele,
		cls)) ele.className += ' ' + cls
}
/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele,
                            cls) {
	if (hasClass(ele,
		cls)) {
		const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
		ele.className = ele.className.replace(reg,
			' ')
	}
}
export function makeMap(str,
                        expectsLowerCase) {
	const map = Object.create(null)
	const list = str.split(',')
	for (let i = 0; i < list.length; i++) {
		map[list[i]] = true
	}
	return expectsLowerCase ? val => map[val.toLowerCase()] : val => map[val]
}
/**
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path) {
	return /^(https?:|mailto:|tel:)/.test(path)
}
/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validUsername(str) {
	const valid_map = ['admin',
		'editor']
	return valid_map.indexOf(str.trim()) >= 0
}
/**
 * @param {string} url
 * @returns {Boolean}
 */
export function validURL(url) {
	const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
	return reg.test(url)
}
/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validLowerCase(str) {
	const reg = /^[a-z]+$/
	return reg.test(str)
}
/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validUpperCase(str) {
	const reg = /^[A-Z]+$/
	return reg.test(str)
}
/**
 * @param {string} str
 * @returns {Boolean}
 */
export function validAlphabets(str) {
	const reg = /^[A-Za-z]+$/
	return reg.test(str)
}
/**
 * @param {string} email
 * @returns {Boolean}
 */
export function validEmail(email) {
	const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
	return reg.test(email)
}
/**
 * @param {string} str
 * @returns {Boolean}
 */
export function isString(str) {
	if (typeof str === 'string' || str instanceof String) {
		return true
	}
	return false
}
/**
 * @param {Array} arg
 * @returns {Boolean}
 */
export function isArray(arg) {
	if (typeof Array.isArray === 'undefined') {
		return Object.prototype.toString.call(arg) === '[object Array]'
	}
	return Array.isArray(arg)
}
export function checkValid({
	                           msg,
	                           errorMsg,
	                           answer,
	                           correctHandler,
	                           cancelHandler
                           }) {
	let sign = prompt(msg)
	if (sign || sign == '' || sign == undefined) {
		if (sign == answer) {
			correctHandler()
		} else {
			if (sign == null) {
				cancelHandler()
			} else {
				if (confirm(errorMsg)) {
					checkValid({
						msg,
						errorMsg,
						answer,
						correctHandler,
						cancelHandler
					})
				} else {
					cancelHandler()
				}
			}
		}
	} else {
		cancelHandler()
	}
}
export function showUploadError(err,
                                file,
                                fileList) {
	const msgJson = JSON.parse(err.message)
	if (msgJson.hasOwnProperty('exception')) {
		const msg = '"' + JSON.stringify(msgJson.exception)
			.split('ApiException:')[1]
		Message({
			type: 'error',
			message: msg
		})
	} else {
		Message({
			type: 'error',
			message: msg
		})
	}
}
export function getUserInfoToStr(obj) {
	let result = null
	try {
		result = obj.store.state.user.userInfo.user
	} catch (e) {
	}
	return result
}
export function toUgroup(sum) {
	let result = undefined
	try {
		const binaryCode = sum.toString(2);
		let index = binaryCode.length - 1;
		const indexs = [];
		for (let i = 0; i < binaryCode.length; i++) {
			if (binaryCode.charAt(i) == '1') {
				indexs.push(index);
			}
			index--;
		}
		result = indexs.map((value) => 1 << value)
			.sort();
	} catch (e) {
	}
	return result
}
export function addUniqueRandomNumber(existingNumbers,
                                      min,
                                      max) {
	// 检查是否可能生成新的不同数字
	if (max - min + 1 <= existingNumbers.length) {
		throw new Error("无法生成新的不同随机数: 范围太小或现有数字过多");
	}
	const numbersSet = new Set(existingNumbers); // 使用Set确保所有元素唯一
	let num;
	do {
		num = Math.floor(Math.random() * (max - min + 1)) + min;
	} while (numbersSet.has(num)); // 确保生成的数字不与已有的重复
	existingNumbers.push(num); // 将新数字添加到数组的末尾
	return existingNumbers; // 返回更新后的数组
}
export function addNextNumber(arr) {
	if (!Array.isArray(arr)) {
		throw new Error("传入参数必须是一个数组");
	}
	// 如果数组为空，则添加数字 1
	if (arr.length === 0) {
		arr.push(1);
	} else {
		// 确保所有元素都是数字并找到最大值
		const maxNum = Math.max(...arr);
		const newNum = maxNum + 1;
		// 检查新生成的数字是否已存在于数组中（理论上不会发生，但为了安全起见）
		if (!arr.includes(newNum)) {
			arr.push(newNum);
		} else {
			throw new Error("意外错误：生成的数字已存在于数组中");
		}
	}
	return arr;
}
//globalVar 根据值，获取名字
export const getGNameVlaueByvv = ({
	                                  type,
	                                  vValue
                                  }) => {
	let index = Object.keys(G[type])
		.findIndex((res) => {
			return G[type][res] == vValue
		})
	return G[type + '_NAME'][Object.keys(G[type])[index]]
}
// 根据任务状态返回不同的颜色
export const getStatusColor = (status) => {
	let num = status
	if (!isNaN(num)) {
		num = parseInt(num)
	}
	switch (num) {
		case G.TASK_STATUS.INITIATE_APPLICATION: // INITIATE_APPLICATION
			return 'success'; // 绿色
		case G.TASK_STATUS.UNDER_APPROVAL: // UNDER_APPROVAL
			return 'warning'; // 黄色
		case G.TASK_STATUS.APPROVAL: // APPROVAL
			return 'primary'; // 蓝色
		case G.TASK_STATUS.REJECT_AND_END: // REJECT_AND_END
			return 'danger'; // 红色
		case G.TASK_STATUS.PREVIEW: // PREVIEW
			return 'primary'; // 深蓝色
		case G.TASK_STATUS.RETURNED: // RETURNED
			return 'danger'; // 深灰色
		case G.TASK_STATUS.RETURNED_ALL: // RETURNED_ALL
			return 'danger'; // 深灰色
		case G.TASK_STATUS.TRANSFERRED: // TRANSFERRED
			return 'primary'; // 绿色
		case G.TASK_STATUS.CANCELED: // CANCELED
			return 'info'; // 红色

		case G.TASK_STATUS.SAVE: // SAVE
			return 'info'; // 蓝色
		case G.TASK_STATUS.RE_SUBMIT: // RE_SUBMIT
			return 'success'; // 黄色
		case G.TASK_STATUS.RE_SUBMIT_ALL: // RE_SUBMIT_ALL
			return 'success'; // 黄色
		default:
			return 'info'; // 默认蓝色
	}
};
// 根据任务状态返回不同的颜色
export const getStatusColorColor = (status) => {
	switch (status) {
		case G.TASK_STATUS.INITIATE_APPLICATION: // INITIATE_APPLICATION
			return '#67C23A'; // 绿色
		case G.TASK_STATUS.UNDER_APPROVAL: // UNDER_APPROVAL
			return '#E6A23C'; // 黄色
		case G.TASK_STATUS.APPROVAL: // APPROVAL
			return '#409EFF'; // 蓝色
		case G.TASK_STATUS.REJECT_AND_END: // REJECT_AND_END
			return '#F56C6C'; // 红色
		case G.TASK_STATUS.PREVIEW: // PREVIEW
			return '#409EFF'; // 深蓝色
		case G.TASK_STATUS.RETURNED: // RETURNED
			return '#909399'; // 深灰色
		case G.TASK_STATUS.RETURNED_ALL: // RETURNED_ALL
			return '#909399'; // 深灰色
		case G.TASK_STATUS.TRANSFERRED: // TRANSFERRED
			return '#67C23A'; // 绿色
		case G.TASK_STATUS.CANCELED: // CANCELED
			return '#F56C6C'; // 红色

		case G.TASK_STATUS.SAVE: // SAVE
			return '#409EFF'; // 蓝色
		case G.TASK_STATUS.RE_SUBMIT: // RE_SUBMIT
			return '#E6A23C'; // 黄色
		case G.TASK_STATUS.RE_SUBMIT_ALL: // RE_SUBMIT_ALL
			return '#E6A23C'; // 黄色
		default:
			return '#409EFF'; // 默认蓝色
	}
};
